package org.gwt.grin.client.features;

import java.util.Map;

import org.gwt.grin.client.Feature;
import org.gwt.grin.client.util.Graphics;

/**
 * A {@code Translator} wraps other features, and adds movement taken from a
 * translator model (represented at runtime by an {@link InterpolatedModel}) to
 * it. The subfeature is translated by the given amount.
 * 
 * @author Bill Foote (http://jovial.com)
 * @author ggeorg
 */
public class Translator extends Modifier {

	public final static int X_FIELD = 0;
	public final static int Y_FIELD = 1;

	public final static int OFFSCREEN = Integer.MIN_VALUE;

	protected InterpolatedModel model;

	private transient int lastDx = OFFSCREEN;
	private transient int lastDy = OFFSCREEN;

	public Translator(String name) {
		super(name, null);

	}

	public void setup(InterpolatedModel model, Feature part) {
		this.part = part;
		this.model = model;
	}

	@Override
	protected Feature createClone(Map<Feature, Feature> clones) {
		if (!isSetup() || activated) {
			throw new IllegalStateException();
		}
		Translator result = new Translator(null);
		result.show = show; // FIXME
		result.part = part.makeNewClone(clones);
		result.lastDx = lastDx;
		result.lastDy = lastDy;
		return result;
	}

	@Override
	protected void initializeClone(Feature original,
			Map<Feature, Feature> clones) {
		super.initializeClone(original, clones);
		Translator other = (Translator) original;
		model = (InterpolatedModel) Feature
				.clonedReference(other.model, clones);
	}

	public InterpolatedModel getModel() {
		return model;
	}

	@Override
	public void nextFrame() {
		assert model.getIsActivated();
		super.nextFrame();
		// Note that at this point, we don't know if our model has advanced to
		// the next frame or not, so we can't depend on its value.
	}

	@Override
	public int getX() {
		int x = model.getField(X_FIELD);
		x += part.getX();
		return x;
	}

	@Override
	public int getY() {
		int y = model.getField(Y_FIELD);
		y += part.getY();
		return y;
	}

	@Override
	public void paintFrame(Graphics gc) {
		int dx = model.getField(X_FIELD);
		int dy = model.getField(Y_FIELD);
		if (dx == OFFSCREEN || dy == OFFSCREEN) {
			return;
		}
		if (dx != lastDx || dy != lastDy) {
			markAsChanged();
			lastDx = dx;
			lastDy = dy;
		}
		gc.translate(dx, dy);
		part.paintFrame(gc);
		gc.translate(-dx, -dy);
	}
}
